package com.kamistoat.netty.netty.simple;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * Netty服务端--BossGroup
 */
public class NettyServer {
    public static void main(String[] args) throws InterruptedException {
        // 创建BossGroup和WorkGroup，直接调用Netty自带的API即可，两者都是 NIOEventLoopGroup
        // BossGroup只处理链接请求，WorkGroup处理业务请求。在实际运行中，两个LoopGroup都是无限循环
        // NIOEventLoopGroup()初始化可传入容量大小，若不传入，则内部的Loop个数默认为CPU(虚拟)核心数*2
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        // 使用Netty自带的API，创建NettyBootStrap配置文件.
        // 在服务端创建 ServerBootStrap，在客户端创建 BootStrap
        // NettyBootStrap允许基于链式编程进行配置
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        try {
            serverBootstrap
                    // 设置两个 NioEventLoopGroup
                    .group(bossGroup, workGroup)
                    // 指定使用 NIOSocketChannel作为该LoopGroup中Loop的channel的实现。
                    // 服务端使用 NioServerSocketChannel， 客户端使用 NioSocketChannel
                    // BossGroup在接收连接请求后会生成 NIOSocketChannel注册到WorkGroup
                    .channel(NioServerSocketChannel.class)
                    // 设置线程队列得到连接个数
                    .option(ChannelOption.SO_BACKLOG, 128)
                    // 设置保持活动连接状态
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    // 为WorkGroup绑定handler处理业务请求，即客户端发送消息事件。
                    // 绑定handler实际上就是为 WorkGroup中 EventLoop 所使用的pipeline添加handler
                    // 直接在channel初始化时进行handler绑定，new ChannelInitializer并实现其方法
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // 获取 pipeline
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            // 在pipeline的最后添加一个 handler，这个handler是我们自行实现的一个NettyHandler类
                            pipeline.addLast(new NettyServerHandler());
                        }
                    });
            System.out.println("服务端 is ready...");

            // 调用bind()方法，生成ChannelFuture对象，然后以异步模式执行bind()方法
            ChannelFuture channelFuture = serverBootstrap.bind(6668).sync();
            // 为Future添加一个监视器，监视器将会以异步执行
            channelFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    // 监视器上来先睡眠5秒，但并不会阻塞整个监听器之外的操作
                    Thread.sleep(5 * 1000);
                    // 查询Future的状态
                    if (channelFuture.isSuccess()) {
                        System.out.println("端口6668绑定成功");
                    } else {
                        System.out.println("端口6668绑定失败");
                    }
                }
            });
            // Listener将以异步模式执行，因此先输出绑定操作，五秒之后输出绑定成功
            System.out.println("绑定操作");


            // 对关闭通道的请求 进行监听。异步模式
            channelFuture.channel().closeFuture().sync();
        } finally {
            // 出现异常时，优雅关闭BossGroup
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }

    }
}
